package channelhandler

import (
	"context"
	"encoding/json"

	"github.com/sirupsen/logrus"

	"monorepo/bin-call-manager/models/ari"
	"monorepo/bin-call-manager/pkg/dbhandler"
)

// HealthCheck checks the given channel is still vaild
func (h *channelHandler) HealthCheck(ctx context.Context, channelID string, retryCount int) {
	log := logrus.WithFields(logrus.Fields{
		"func":        "HealthCheck",
		"channel_id":  channelID,
		"retry_count": retryCount,
	})

	// exceeded max retry count.
	// hangup the channel info.
	if retryCount > defaultHealthMaxRetryCount {
		log.Infof("Exceeded max channel health check retry count. Destroy the channel. channel_id: %s", channelID)

		// publish the fake channel destroyed event
		h.publishFakeEventChannelDestoryed(ctx, channelID)
		return
	}

	// get channel
	cn, err := h.Get(ctx, channelID)
	if err != nil {
		// could not get channel info. No need to retry check. Nothing to do.
		log.Errorf("Could not get the channel from the database. channel_id: %s, err: %v", channelID, err)
		return
	}

	// check if the channel has deleted already, we don't go further.
	if cn.TMEnd != dbhandler.DefaultTimeStamp {
		// the channel has hungup already. no need to check the health anymore
		return
	}

	_, err = h.reqHandler.AstChannelGet(ctx, cn.AsteriskID, cn.ID)
	if err != nil {
		// could not get the asterisk channel info. consider the channel has hungup.
		// we are giving another try with increased retry count.
		// because we are expecting the other event handler(ChannelDestroyed) handles the event correctly.
		retryCount++
	} else {
		retryCount = 0
	}

	// send health check.
	if err := h.reqHandler.CallV1ChannelHealth(ctx, channelID, defaultHealthDelay, retryCount); err != nil {
		log.Errorf("Could not send the channel check request. err: %v", err)
		return
	}
}

// publishFakeEventChannelDestoryed publishes the fake ChannelDestroyed ARI event to the call-manager's subscribe queue.
func (h *channelHandler) publishFakeEventChannelDestoryed(ctx context.Context, channelID string) {
	log := logrus.WithFields(logrus.Fields{
		"func":       "publishFakeEventChannelDestoryed",
		"channel_id": channelID,
	})

	tmp := &ari.ChannelDestroyed{
		Event: ari.Event{},
		Channel: ari.Channel{
			ID: channelID,
		},
		CauseTxt: "channel destroy generated by the call-manager",
		Cause:    ari.ChannelCauseNormalClearing,
	}

	m, err := json.Marshal(tmp)
	if err != nil {
		log.Errorf("Could not marshal the channel info. err: %v", err)
		return
	}

	if errEvent := h.reqHandler.CallPublishEvent(ctx, string(ari.EventTypeChannelDestroyed), "asterisk-proxy", "application/json", m); errEvent != nil {
		return
	}
}
